﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using ERMSys.Framework.ObjectContextManagement;
using System.Data.Objects;
using System.Configuration;
using System.Reflection;
using System.Data.Metadata.Edm;
using System.Data;

namespace Se7en.Admin.Common
{
    public sealed class UnitOfWorkScope<T> : ObjectContextScope<T> where T : ObjectContext, new()
    {
        /// <summary>
        /// Default constructor. Object changes are not automatically saved at the 
        /// end of the scope.
        /// </summary>
        public UnitOfWorkScope()
            : base()
        { }

        /// <summary>
        /// Parameterized constructor.
        /// </summary>
        /// <param name="saveAllChangesAtEndOfScope">
        /// A boolean value that indicates whether to automatically save 
        /// all object changes at end of the scope.
        /// </param>
        public UnitOfWorkScope(bool saveAllChangesAtEndOfScope)
            : base(saveAllChangesAtEndOfScope)
        { }
    }

    public class ContextManagement<T> where T : ObjectContext, new()
    {
        private ObjectContextManager<T> _objectContextManager;

        /// <summary>
        /// Returns the current ObjectContextManager instance. Encapsulated the 
        /// _objectContextManager field to show it as an association on the class diagram.
        /// </summary>
        private ObjectContextManager<T> ObjectContextManager
        {
            get { return _objectContextManager; }
            set { _objectContextManager = value; }
        }

        /// <summary>
        /// Returns a NorthwindObjectContext object. 
        /// </summary>
        public T OC
        {
            get
            {
                if (ObjectContextManager == null)
                    this.InstantiateObjectContextManager();

                //Allow dot(.) to get Object Reference
                ObjectContextManager.ObjectContext.ContextOptions.LazyLoadingEnabled = true;
                return ObjectContextManager.ObjectContext;
            }
        }

        /// <summary>
        /// Instantiates a new ObjectContextManager based on application configuration settings.
        /// </summary>
        private void InstantiateObjectContextManager()
        {
            /* Retrieve ObjectContextManager configuration settings: */
            Hashtable ocManagerConfiguration = ConfigurationManager.GetSection("V7.Configuration.ObjectContext") as Hashtable;
            if (ocManagerConfiguration != null && ocManagerConfiguration.ContainsKey("managerType"))
            {
                string managerTypeName = ocManagerConfiguration["managerType"] as string;
                if (string.IsNullOrEmpty(managerTypeName))
                    throw new ConfigurationErrorsException("The managerType attribute is empty.");
                else
                    managerTypeName = managerTypeName.Trim().ToLower();

                try
                {
                    /* Try to create a type based on it's name: */
                    Assembly frameworkAssembly = Assembly.GetAssembly(typeof(ObjectContextManager<>));
                    /* We have to fix the name, because its a generic class: */
                    Type managerType = frameworkAssembly.GetType(managerTypeName + "`1", true, true);
                    managerType = managerType.MakeGenericType(typeof(T));

                    /* Try to create a new instance of the specified ObjectContextManager type: */
                    this.ObjectContextManager = Activator.CreateInstance(managerType) as ObjectContextManager<T>;
                }
                catch (Exception e)
                {
                    throw new ConfigurationErrorsException("The managerType specified in the configuration is not valid.", e);
                }
            }
            else
                throw new ConfigurationErrorsException("A V7.Configuration.ObjectContext tag or its managerType attribute is missing in the configuration.");
        }
    }
}

